#ifndef PW_PBL_CASTOP_HPP
#define PW_PBL_CASTOP_HPP

#include <utility>

namespace pw_pbl
{
	/// 安全类型转换操作
	/// 不需要板参数，指定模板参数是为了解决多个相同空基类导致布局增加填充字节的问题
	template <auto = [] {}>
	struct CastOp
	{
	private:
		template <typename TRAIT, typename SELF>
		using steal_const = std::conditional_t<std::is_const_v<std::remove_reference_t<SELF>>, const TRAIT, TRAIT>;

		template <typename TRAIT, typename SELF>
		using steal_const_and_ref = std::conditional_t<std::is_reference_v<SELF>, steal_const<TRAIT, SELF> &, steal_const<TRAIT, SELF> &&>;

		template <typename SELF, typename IMP>
		static constexpr bool can_cast_to = std::convertible_to<SELF, IMP> && (!std::is_reference_v<IMP> || (sizeof(IMP) <= sizeof(SELF) && alignof(IMP) <= alignof(SELF)));

	public:
		/// 将自身引用静态转换为IMP类型
		template <typename IMP, typename SELF> requires can_cast_to<SELF, IMP>
		constexpr IMP cast_to(this SELF &&self)
		{
			return static_cast<IMP>(std::forward<SELF>(self));
		}

		/// 将自身引用静态转换为TRAIT<std::decay_t<SELF>, PARMS...>类型
		template <template <typename, typename...> class TRAIT, typename... PARMS, typename SELF> requires std::convertible_to<SELF, TRAIT<std::decay_t<SELF>, PARMS...>>
		constexpr TRAIT<std::decay_t<SELF>, PARMS...> cast_to(this SELF &&self)
		{
			return static_cast<TRAIT<std::decay_t<SELF>, PARMS...>>(std::forward<SELF>(self));
		}

		/// 将自身引用静态转换为TRAIT<std::decay_t<SELF>, PARMS...>类型
		template <template <typename, auto...> class TRAIT, auto... PARMS, typename SELF> requires std::convertible_to<SELF, TRAIT<std::decay_t<SELF>, PARMS...>>
		constexpr TRAIT<std::decay_t<SELF>, PARMS...> cast_to(this SELF &&self)
		{
			return static_cast<TRAIT<std::decay_t<SELF>, PARMS...>>(std::forward<SELF>(self));
		}

		/// 将自身引用当成TRAIT的引用，要求相互之间有继承关系，通常用于类型定义之外扩展方法定义
		template <typename TRAIT, typename SELF> requires(!std::is_reference_v<TRAIT> && can_cast_to<SELF, steal_const_and_ref<TRAIT, SELF>>)
		constexpr steal_const_and_ref<TRAIT, SELF> cast_as(this SELF &&self)
		{
			return static_cast<steal_const_and_ref<TRAIT, SELF>>(std::forward<SELF>(self));
		}

		/// 将自身引用当成TRAIT<std::decay_t<SELF>, PARMS...>的引用，要求相互之间有继承关系，通常用于类型定义之外扩展方法定义
		template <template <typename, typename...> class TRAIT, typename... PARMS, typename SELF> requires can_cast_to<SELF, steal_const_and_ref<TRAIT<std::decay_t<SELF>, PARMS...>, SELF>>
		constexpr steal_const_and_ref<TRAIT<std::decay_t<SELF>, PARMS...>, SELF> cast_as(this SELF &&self)
		{
			return static_cast<steal_const_and_ref<TRAIT<std::decay_t<SELF>, PARMS...>, SELF>>(std::forward<SELF>(self));
		}

		/// 将自身引用当成TRAIT<std::decay_t<SELF>, PARMS...>的引用，要求相互之间有继承关系，通常用于类型定义之外扩展方法定义
		template <template <typename, auto...> class TRAIT, auto... PARMS, typename SELF> requires can_cast_to<SELF, steal_const_and_ref<TRAIT<std::decay_t<SELF>, PARMS...>, SELF>>
		constexpr steal_const_and_ref<TRAIT<std::decay_t<SELF>, PARMS...>, SELF> cast_as(this SELF &&self)
		{
			return static_cast<steal_const_and_ref<TRAIT<std::decay_t<SELF>, PARMS...>, SELF>>(std::forward<SELF>(self));
		}
	};

} // namespace pw_pbl

#endif // PW_PBL_CASTOP_HPP
